#include<t_stdio.h>
#include<t_file.h>
#include<stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include<unistd.h>
static struct iovec*vs=NULL;
void sig_process(int signo){//信号处理函数
    printf("catch a exit signal..\n");
    free(vs);
    _exit(0);
}

#define port 8888//端口号
#define backlog 2//最大监听数量

//业务处理逻辑
void process_conn_server(int s){
    char buffer [30];
    ssize_t size=0; //向量的缓冲区
    
    //申请3个向量空间
    struct iovec * v = (struct iovec *)malloc(3*sizeof(struct iovec));
    if(!v) E_MSG("malloc",-1);

    vs = v;//挂接全局变量，易于释放管理

    v[0].iov_base= buffer;//每个向量十个地址空间
    v[1].iov_base= buffer+10;
    v[2].iov_base= buffer+20;
    v[0].iov_len = v[1].iov_len = v[2].iov_len = 10;//初始化长度为10
    for(;;){
        size = readv(s, v , 3);// 从套接字中读取数据放入数据缓冲区
        if(size == 0){
            return ;
        }
        //构建响应字符
        sprintf(v[0].iov_base,"%d",size);
        sprintf(v[1].iov_base,"bytes alter");
        sprintf(v[2].iov_base,"ogether\n");

        //设置写入数据的长度
        v[0].iov_len = strlen(v[0].iov_base);
        v[1].iov_len = strlen(v[1].iov_base);
        v[2].iov_len = strlen(v[2].iov_base);

        writev(s , v , 3);//发送给客户端
    }

}
int main(int argc ,char * argv[])
{
    int ss ,sc;//服务器和客户端的套接字文件描述符
    struct  sockaddr_in server_addr;//服务器地址结构
    struct  sockaddr_in client_addr;//客户端地址结构
    pid_t pid;//创建子进程进行分叉进行
    signal(SIGINT,sig_process);//添加sigint信号到信号掩码
    signal(SIGPIPE,sig_process);
    
    ss = socket(AF_INET,SOCK_STREAM,0);// 创建服务器套接字
    if(ss < 0) E_MSG("socket",-1);

    bzero(&server_addr,sizeof(server_addr));//将地址清零

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);//本地地址
    server_addr.sin_port=htons(port);//设置端口

    //绑定本地到套接字符
    int err = bind(ss,(struct  sockaddr * )&server_addr,sizeof(server_addr));
    if(err < 0)E_MSG("bind",-1);

    err = listen(ss,backlog);//创建监听队列
    for(;;){
        int addrlen = sizeof(struct sockaddr);
        sc = accept(ss,(struct sockaddr * )&client_addr,&addrlen);//获取用户套接字
        if(sc < 0)continue;//客户端出错，结束这次循环，继续监听客户；
        pid = fork();//创建新的子进程来处理当前连接客户端；
        if(pid==0){
            close(ss);// 子进程中关闭服务端
            process_conn_server(sc);
        }
        else {
            close(sc);//父进程关闭客户端连接，继续监听;
        }
    }


    return 0;
}